﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml;
using Jacobi.Vst.Framework;
using Aleator.Core;
using System.Runtime.InteropServices;
using Sanford.Multimedia.Midi;


namespace Aleator
{
    /// <summary>
    /// Interaction logic for AleatorControl.xaml
    /// </summary>
    public partial class AleatorControl : UserControl
    {
        #region Members
        private Session m_session;

        private IVstMidiProcessor m_pluginProcessor;
        #endregion

        #region Constructor

        /// <summary>
        /// Generic contructor
        /// </summary>
        public AleatorControl()
        {
            SmartDispatcher.Initialize(Dispatcher.CurrentDispatcher);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// React to transport and turn buttons on/off accordingly
        /// </summary>
        /// <param name="on"></param>
        public void ToggleButtons(int on)
        {
            if (!Session.TransportOverride)
            {
                bool display = false;

                if (on == 2)
                    PlayButton_Click(this, null);
                else
                {
                    StopButton_Click(this, null);
                    display = true;
                }

                SmartDispatcher.BeginInvoke(delegate
                {
                    PreviousButton.IsEnabled = display;
                    RewindButton.IsEnabled = display;
                    PlayButton.IsEnabled = display;
                    StopButton.IsEnabled = display;
                    PauseButton.IsEnabled = display;
                    FastForwardButton.IsEnabled = display;
                    NextButton.IsEnabled = display;
                });
            }
        }

        private void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == Session.CurrentNoteIsPlayingPropertyName && Session.CurrentDisplayNote != null)
            {
                if (Session.CurrentNoteIsPlaying == true)
                {
                    System.Diagnostics.Debug.WriteLine("Changing note color to red");
                    NoteText.Foreground = Brushes.Red;
                    CurrentChordText.Foreground = Brushes.Red;
                    IntervalText.Foreground = Brushes.Red;
                    OctaveText.Foreground = Brushes.Red;
                    LengthText.Foreground = Brushes.Red;
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("Changing note color to red");
                    NoteText.Foreground = Brushes.White;
                    CurrentChordText.Foreground = Brushes.White;
                    IntervalText.Foreground = Brushes.White;
                    OctaveText.Foreground = Brushes.White;
                    LengthText.Foreground = Brushes.White;
                }
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Note for detail display
        /// </summary>
        public ConcreteNote CurrentNote;

        /// <summary>
        /// This has to be included in order for the UO to work with the plugin
        /// </summary>
        public void ProcessIdle()
        {
            //Do nothing
        }

        /// <summary>
        /// The MIDI processor of this UI's plugin
        /// </summary>
        public IVstMidiProcessor PluginProcessor
        {
            get
            {
                return m_pluginProcessor;
            }
            set
            {
                m_pluginProcessor = value;
            }
        }

        /// <summary>
        /// Session currently running
        /// </summary>
        public Core.Session Session
        {
            get
            {
                return m_session;
            }
            set
            {
                m_session = value;
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Start up the session and the DataContext of the control. For some reason this only works on startup when called from the PluginEditor
        /// </summary>
        public void AddSessionBindings()
        {
            Session = new Session(this.PluginProcessor, true);
            Session.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Session_PropertyChanged);
            Aleator.Core.Session.StaticPropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Session_PropertyChanged);

            Session.PrepareUIProperties();

            InitializeComponent();

            _this.DataContext = Session;
            _this.Unloaded += Session_Unload;
        }

        private void NoteComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox l = (ComboBox)sender;

            if (l.SelectedItem != null)
                Session.CurrentDisplayNote = (ConcreteNote)l.SelectedItem;
        }

        private void PlayButton_Click(object sender, RoutedEventArgs e)
        {
            if (Session != null)
            {
                if (!Session.Clock.IsRunning)
                    Session.Start();
                else
                    Session.HoldPhrase = false;
            }
            else
            {
                AddSessionBindings();
                Session.Start();
                Session.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Session_PropertyChanged);
            }
        }

        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            if (Session != null)
            {
                Session.PropertyChanged -= Session_PropertyChanged;
                Session.Stop();

                //Session = null;
            }
            else
                Session.Kill();
        }

        private void PauseButton_Click(object sender, RoutedEventArgs e)
        {
            Session.HoldPhrase = true;
        }

        private void PreviousButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Session.ChangeComposition(-1);
            }
            catch (ArgumentOutOfRangeException)
            {
                MessageBox.Show("Already at the end of the suite.");
            }
        }

        private void NextButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Session.ChangeComposition(1);
            }
            catch (ArgumentOutOfRangeException)
            {
                MessageBox.Show("Already at the end of the suite.");
            }
        }

        private void RewindButton_Click(object sender, RoutedEventArgs e)
        {
            Session.ChangeProgression(-1);
        }

        private void FastForwardButton_Click(object sender, RoutedEventArgs e)
        {
            Session.ChangeProgression(1);
        }

        private void Session_Unload(object sender, EventArgs e)
        {
            if (Session != null)
            {
                Session.Stop();
                Session = null;
            }
        }
        #endregion

        //private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        //{

        //    if (TempoSlider.Minimum != 90 || TempoSlider.Maximum != 90)
        //    {
        //        if (e.NewValue < e.OldValue && e.NewValue != Session.Tempo)
        //        {
        //            Session.Tempo -= e.OldValue - e.NewValue;
        //        }
        //        else if (e.NewValue != Session.Tempo)
        //        {
        //            Session.Tempo += e.NewValue - e.OldValue;
        //        }
        //    }
        //}

        private void drumRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Drum);
        }

        private void bassRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Bass);
        }

        private void rhythmRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Rhythm);
        }

        private void leadRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Melody);
        }

        private void arpRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Arp);
        }

        private void utilityRecycle_click(object sender, RoutedEventArgs e)
        {
            Session.ReTrigger(PhraseFactory.PhraseType.Utility);
        }

        private void Phrase_Mute(object sender, RoutedEventArgs e)
        {
            string name = (sender as ToggleButton).Name;

            switch (name)
            {
                case "DrumMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Drum);
                    break;
                case "BassMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Bass);
                    break;
                case "RhythmMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Rhythm);
                    break;
                case "LeadMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Melody);
                    break;
                case "ArpMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Arp);
                    break;
                case "UtilityMuteButton":
                    Session.Mute(PhraseFactory.PhraseType.Utility);
                    break;
            }
        }

        private void Phrase_Unmute(object sender, RoutedEventArgs e)
        {
            string name = (sender as ToggleButton).Name;

            switch (name)
            {
                case "DrumMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Drum);
                    break;
                case "BassMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Bass);
                    break;
                case "RhythmMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Rhythm);
                    break;
                case "LeadMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Melody);
                    break;
                case "ArpMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Arp);
                    break;
                case "UtilityMuteButton":
                    Session.UnMute(PhraseFactory.PhraseType.Utility);
                    break;
            }
        }

        private void CompositionsComboBox_SourceUpdated(object sender, DataTransferEventArgs e)
        {
            (sender as ComboBox).SelectedIndex = 0;
        }

        private void CompositionsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //Session.ModeCheck();
        }
    }
}